using Unity.Burst;                     // 引入 Burst 编译相关功能，用于高性能 Job 系统
using Unity.Collections;               // 引入 Native 容器（如 NativeArray），用于多线程安全的数据存储
using Unity.Jobs;                      // 引入 Unity Job 系统，用于多线程任务调度
using Unity.Mathematics;               // 引入数学库，例如 float3、PI 等数学类型和常量

using static Unity.Mathematics.math;   // 静态导入 math 命名空间，这样可以直接使用 float3, PI 等，无需写 math.xxx

// 该 Job 被标记为 IJobFor 类型，表示它是一个可被并行 “for 循环” 执行的 Job
// BurstCompile 特性表示该 Job 将通过 Burst 编译器进行优化，以大幅提升运行效率
// 参数说明：FloatPrecision.Standard 表示使用标准浮点精度；FloatMode.Fast 表示采用快速但不那么精确的浮点模式
[BurstCompile(FloatPrecision.Standard, FloatMode.Fast)]
struct UpdateVisualizationJob : IJobFor
{
    // ===== 静态只读字段：数字 0~6 以及特殊状态的位图定义（用于控制方块哪些部分显示/隐藏） =====

    // 定义了一个静态的、只读的 ulong 数组，每个元素是一个 64 位掩码（bitmask）
    // 每个数字（0~6）对应一个 7x5 的点阵图案（类似七段数码管或方块拼成的数字/符号）
    // 每个 bit 代表一个小块（block）是否应该被 “点亮 / 显示 / 变形”
    // 总共预定义了 11 种状态：数字 0~6、地雷、已确定标记、误标、不确定标记、隐藏
    readonly static ulong[] bitmaps =
    {
        0b00000_01110_01010_01010_01010_01110_00000, // 0  --> 数字 0 的显示图案（1 表示该位置的 block 要显示/变化）
        0b00000_00100_00110_00100_00100_01110_00000, // 1  --> 数字 1
        0b00000_01110_01000_01110_00010_01110_00000, // 2  --> 数字 2
        0b00000_01110_01000_01110_01000_01110_00000, // 3  --> 数字 3
        0b00000_01010_01010_01110_01000_01000_00000, // 4  --> 数字 4
        0b00000_01110_00010_01110_01000_01110_00000, // 5  --> 数字 5
        0b00000_01110_00010_01110_01010_01110_00000, // 6  --> 数字 6

        // 下面是特殊状态，不是数字，而是游戏中的标记或地雷状态
        0b00000_10001_01010_00100_01010_10001_00000, // mine      --> 地雷符号的点阵
        0b00000_00000_00100_01110_00100_00000_00000, // marked sure --> 已确认安全标记（比如插旗且确实没雷）
        0b11111_11111_11011_10001_11011_11111_11111, // marked mistaken --> 错误标记（比如插旗但其实是雷）
        0b00000_01110_01010_01000_00100_00000_00100, // marked unsure --> 不确定的标记（比如问号标记）
        0b00000_00000_00000_00000_00000_00000_00000  // hidden      --> 隐藏状态（什么都不显示）
    };

    // ===== 静态只读字段：与上述 bitmaps 对应的颜色配置 =====
    // 每个符号（数字或状态）对应一个基础颜色，数值越大表示颜色越亮/越突出
    static readonly float3[] colorations =
    {
        1.00f * float3(1f, 1f, 1f), // 0  --> 数字 0 的颜色（白色，亮度普通）
        1.00f * float3(0f, 0f, 1f), // 1  --> 数字 1 （蓝色）
        2.00f * float3(0f, 1f, 1f), // 2  --> 数字 2 （青色，更亮）
        5.00f * float3(0f, 1f, 0f), // 3  --> 数字 3 （绿色，很亮）
        10.0f * float3(1f, 1f, 0f), // 4  --> 数字 4 （黄色，非常亮）
        20.0f * float3(1f, 0f, 0f), // 5  --> 数字 5 （红色，极亮）
        20.0f * float3(1f, 0f, 1f), // 6  --> 数字 6 （紫色，极亮）

        30.0f * float3(1f, 0f, 1f), // mine      --> 地雷（亮紫色，突出危险）
        1.00f * float3(1f, 0f, 0f), // marked sure --> 已确认标记（红色）
        50.0f * float3(1f, 0f, 1f), // marked mistaken --> 错误标记（很亮的紫红，警示）
        0.25f * float3(1f, 1f, 1f), // marked unsure --> 不确定标记（很淡的白色）
        0.00f * float3(0f, 0f, 0f)  // hidden      --> 隐藏（全黑 / 不显示）
    };

    // ===== 枚举：定义各种格子内容的符号类型（用于索引 bitmaps 和 colorations）=====
    enum Symbol
    {
        Mine = 7,           // 地雷，对应 bitmaps[7]
        MarkedSure,         // 已确认的安全标记，对应 bitmaps[8]
        MarkedMistaken,     // 错误标记，对应 bitmaps[9]
        MarkedUnsure,       // 不确定标记，对应 bitmaps[10]
        Hidden              // 隐藏（未翻开），对应 bitmaps[11]
    };

    // ===== 工具方法：根据 CellState（格子状态）获取对应的符号索引 =====
    // 该方法通过判断格子的状态（是否翻开、是否是地雷、是否有标记等），返回一个 int，用于索引 bitmaps 和 colorations
    static int GetSymbolIndex (CellState state) =>
        state.Is(CellState.Revealed) ?          // 如果格子是已翻开状态
            state.Is(CellState.Mine) ?          // 且是地雷 → 符号索引为 Mine (7)
                (int)Symbol.Mine :
            state.Is(CellState.MarkedSure) ?    // 不是地雷但是被标记为“确定安全” → MarkedMistaken (8)
                (int)Symbol.MarkedMistaken :
            (int)state.Without(CellState.Revealed) :  // 否则返回数字（0~6），即格子中的数字本身（去掉了 Revealed 状态）
        state.Is(CellState.MarkedSure) ?        // 如果格子未翻开但是被标记为确定安全 → MarkedSure (8)
            (int)Symbol.MarkedSure :
        state.Is(CellState.MarkedUnsure) ?      // 未翻开但被标记为不确定 → MarkedUnsure (10)
            (int)Symbol.MarkedUnsure :
        (int)Symbol.Hidden;                     // 其它情况（未翻开、无标记）→ Hidden (11)

    // ===== 可写入的 Native 数组，用于存储每个小块的位置、颜色、涟漪效果 =====
    [NativeDisableParallelForRestriction]
    public NativeArray<float3> positions;  // 每个小块的位置信息（可被 Job 并行修改）
    [NativeDisableParallelForRestriction]
    public NativeArray<float3> colors;     // 每个小块的颜色信息（可被 Job 并行修改）
    [NativeDisableParallelForRestriction]
    public NativeArray<float3> ripples;    // 每个涟漪的位置与强度信息（用于模拟水波纹扩散效果）

    // 当前帧中存在的涟漪总数
    public int rippleCount;

    // 只读的网格数据，提供每个格子的状态信息（是否翻开、是否地雷、是否标记等）
    [ReadOnly]
    public Grid grid;

    // ===== 核心方法：对每个格子（i）执行一次，更新其所有小块的位置和颜色 =====
    public void Execute (int i)
    {
        // 每个格子包含多个小块（block），blockOffset 是该格子所有 blocks 在全局数组中的起始索引
        int blockOffset = i * GridVisualization.blocksPerCell;

        // 获取当前格子 i 的状态对应的符号索引（比如是数字3，还是地雷，还是标记等）
        int symbolIndex = GetSymbolIndex(grid[i]);

        // 根据符号索引，取得对应的位图（控制哪些小块显示/变形）
        ulong bitmap = bitmaps[symbolIndex];

        // 根据符号索引，取得对应的颜色基值（用于着色这些小块）
        float3 coloration = colorations[symbolIndex];

        // 遍历该格子中的每一个小块（block）
        for (int bi = 0; bi < GridVisualization.blocksPerCell; bi++)
        {
            // 判断当前小块是否需要被 “改变 / 显示”（由位图中的某一位决定）
            bool altered = (bitmap & ((ulong)1 << bi)) != 0;

            // 获取该小块当前的位置
            float3 position = positions[blockOffset + bi];

            // 计算该位置上的 “涟漪累积效果”（比如水波经过时产生的下沉效果）
            float ripples = AccumulateRipples(position);

            // 根据是否被 “altered”（是否属于要显示的图案一部分），调整该 block 的 Y 轴高度
            // 被 altered 的块会略微抬升（0.5f），并且受涟漪影响下沉
            position.y = (altered ? 0.5f : 0f) - 0.5f * ripples;

            // 更新该小块的位置
            positions[blockOffset + bi] = position;

            // 计算该小块的颜色：
            // - 如果是 altered，则使用对应的 coloration；
            // - 否则使用默认的 0.5f（可能是灰色或暗色）
            // 并且根据涟漪强度稍稍变暗（1f - 0.05f * ripples）
            colors[blockOffset + bi] =
                (altered ? coloration : 0.5f) * (1f - 0.05f * ripples);
        }
    }

    // ===== 辅助方法：计算某个位置受到所有涟漪影响后的总下沉量 =====
    float AccumulateRipples (float3 position)
    {
        float sum = 0f; // 总涟漪影响值

        // 遍历当前所有的涟漪效果
        for (int r = 0; r < rippleCount; r++)
        {
            // 获取第 r 个涟漪的位置与强度
            float3 ripple = ripples[r];

            // 计算当前 block 位置（xz平面）与涟漪中心（ripple.xy）的距离
            // ripple.z 是涟漪的强度因子（0~1范围？）
            float d = 50f * ripple.z - distance(position.xz, ripple.xy);

            // 如果距离 d 处于 (0, 10) 范围内，说明该 block 处于涟漪的影响范围内
            if (0 < d && d < 10f)
            {
                // 计算涟漪的影响值：
                // - (1 - cos(...)) 生成一个 0~1 的波动曲线，模拟水波的起伏
                // - (1 - ripple.z * ripple.z) 根据涟漪强度减弱影响
                sum += (1f - cos(d * 2f * PI / 10f)) * (1f - ripple.z * ripple.z);
            }
        }

        // 返回该位置受到的总涟漪影响（用于下沉效果）
        return sum;
    }
}